#include "misc.h"



statisticTracker::statisticTracker(size_t dataSize) : size(dataSize),
		data(new float[dataSize]), index(0), div_range(1),
		min_val(0), max_val(1), stdev(1), mu(0), 
		var(1), stdev_2(2){
	for(;index<size; ++index)
		data[index]=0;
	index=0;
}
void statisticTracker::resize(size_t dataSize){
	delete [] data;
	size=dataSize;
	index=0;
	data = new float[size];
	for(; index<size; ++index)
		data[index]=0;
	index=0;
}
void statisticTracker::addData(float point){
	data[index++]=point;
	if(index>=size)
		index=0;
}
void statisticTracker::doCalculations(bool a){
	mu=0;
	min_val=max_val=data[0];
	for(size_t i=0; i<size; ++i){
		mu+=data[i];
		min_val=std::min(min_val, data[i]);
		max_val=std::max(max_val, data[i]);
	}
	mu/=size;
	var=0;
	for(size_t i=0; i<size; ++i){
		var+=(data[i]-mu)*(data[i]-mu);
	}
	var+=1; var/=(size-1);
	stdev_2 = 2 * (stdev = sqrt(var));
	div_range=max_val-min_val;
	div_range=div_range ? div_range : 1;
}
void statisticTracker::doCalculations(float* extData, size_t s, bool a){
	mu=0;
	min_val=max_val=data[0];
	float cp;
	for(size_t i=0; i<s; ++i){
		mu+=cp=cabs(extData[i], a);
		min_val=std::min(min_val, cp);
		max_val=std::max(max_val, cp);
	}
	mu/=size;
	var=0;
	for(size_t i=0; i<s; ++i){
		var+=((cp=cabs(extData[i], a))-mu)*(cp-mu);
	}
	var+=1; var/=(s-1);
	stdev_2 = 2 * (stdev = sqrt(var));
	div_range=max_val-min_val;
	div_range=div_range ? div_range : 1;
}
float statisticTracker::linearTransform(float point) const{ return (point-min_val)/div_range; }
float statisticTracker::normalTransform(float point) const{ return std::max(0.0f , std::min(1.0f , 0.5f+(point-mu)/stdev_2)); }
float statisticTracker::absoluteTransform(float point) const{ return std::max(0.0f, point/max_val); }
float statisticTracker::minimum() const{ return min_val; }
float statisticTracker::maximum() const{ return max_val; }
float statisticTracker::average() const{ return mu; }
float statisticTracker::deviation() const{ return stdev; }


vec2i::vec2i(int nx, int ny) : x(nx), y(ny) {}
vec2i::vec2i(const vec2i& other) : x(other.x), y(other.y) {}
vec2i::vec2i(const vec2f& other) : x(int(other.x)), y(int(other.y)) {}
vec2i& vec2i::operator =(const vec2i& other){ x=other.x; y=other.y; return *this;}
vec2i& vec2i::operator =(const vec2f& other){ x=int(other.x); y=int(other.y); return *this;}
int vec2i::dot(const vec2i& r) const { return x*r.x+y*r.y; }
int vec2i::cross(const vec2i& r) const {return x*r.y -y*r.x; }
float vec2i::magnitude() const { return sqrtf(float(x*x+y*y)); }
vec2f vec2i::normalized() const { return vec2f(*this)/magnitude(); }
vec2i& operator+=(vec2i& l, const vec2i& r){
	l.x+=r.x; l.y+=r.y;
	return l;
}
vec2i& operator-=(vec2i& l, const vec2i& r){
	l.x-=r.x; l.y-=r.y;
	return l;
}
vec2i& operator*=(vec2i& l, const vec2i& r){
	l.x*=r.x; l.y*=r.y;
	return l;
}
vec2i& operator/=(vec2i& l, const vec2i& r){
	l.x/=r.x; l.y/=r.y;
	return l;
}
vec2i& operator*=(vec2i& l, int r){
	l.x*=r;
	l.y*=r;
	return l;
}
vec2i& operator/=(vec2i& l, int r){
	l.x/=r;
	l.y/=r;
	return l;
}
vec2i& operator*=(vec2i& l, float r){
	l.x=(int)(l.x*r); l.y=(int)(l.y*r);
	return l;
}
vec2i& operator/=(vec2i& l, float r){
	l.x=(int)(l.x/r); l.y=(int)(l.y/r);
	return l;
}
vec2i& operator<<=(vec2i& l, int r){
	l.x<<=r; l.y<<=r;
	return l;
}
vec2i& operator>>=(vec2i& l, int r){
	l.x>>=r; l.y>>=r;
	return l;
}
vec2i operator+(const vec2i& l, const vec2i& r){
	return vec2i(l.x+r.x, l.y+r.y);
}
vec2i operator-(const vec2i& l, const vec2i& r){
	return vec2i(l.x-r.x, l.y-r.y);
}
vec2i operator*(const vec2i& l, const vec2i& r){
	return vec2i(l.x*r.x, l.y*r.y);
}
vec2i operator/(const vec2i& l, const vec2i& r){
	return vec2i(l.x/r.x, l.y/r.y);
}
vec2i operator*(const vec2i& l, int r){
	return vec2i(l.x*r, l.y*r);
}
vec2i operator/(const vec2i& l, int r){
	return vec2i(l.x/r, l.y/r);
}
vec2i operator*(const vec2i& l, float r){
	return vec2i((int)(l.x*r), (int)(l.y*r));
}
vec2i operator/(const vec2i& l, float r){
	return vec2i((int)(l.x/r), (int)(l.y/r));
}
vec2i operator<<(const vec2i& l, int r){
	return vec2i(l.x<<r, l.y<<r);
}
vec2i operator>>(const vec2i& l, int r){
	return vec2i(l.x>>r, l.y>>r);
}
vec2i operator*(int l, const vec2i& r){
	return r*l;
}
vec2i operator-(const vec2i& r){
	return vec2i(-r.x, -r.y);
}
bool operator==(const vec2i& l, const vec2i& r){
	return l.x==r.x && l.y==r.y;
}
bool operator!=(const vec2i& l, const vec2i& r){
	return !(l==r);
}


vec2f::vec2f(float nx, float ny) : x(nx), y(ny) {}
vec2f::vec2f(const vec2f& other) : x(other.x), y(other.y) {}
vec2f::vec2f(const vec2i& other) : x(other.x), y(other.y) {}
vec2f& vec2f::operator =(const vec2f& other){ x=other.x; y=other.y; return *this;}
vec2f& vec2f::operator =(const vec2i& other){ x=other.x; y=other.y; return *this;}
float vec2f::dot(const vec2f& r) const { return x*r.x+y*r.y; }
float vec2f::cross(const vec2f& r) const {return x*r.y -y*r.x; }
float vec2f::magnitude() const { return sqrtf(x*x+y*y); }
vec2f vec2f::normalized() const { return (*this)/magnitude(); }
vec2f& operator+=(vec2f& l, const vec2f& r){
	l.x+=r.x; l.y+=r.y;
	return l;
}
vec2f& operator-=(vec2f& l, const vec2f& r){
	l.x-=r.x; l.y-=r.y;
	return l;
}
vec2f& operator*=(vec2f& l, const vec2f& r){
	l.x*=r.x; l.y*=r.y;
	return l;
}
vec2f& operator/=(vec2f& l, const vec2f& r){
	l.x/=r.x; l.y/=r.y;
	return l;
}
vec2f& operator*=(vec2f& l, float r){
	l.x*=r;
	l.y*=r;
	return l;
}
vec2f& operator/=(vec2f& l, float r){
	l.x/=r;
	l.y/=r;
	return l;
}
vec2f operator+(const vec2f& l, const vec2f& r){
	return vec2f(l.x+r.x, l.y+r.y);
}
vec2f operator-(const vec2f& l, const vec2f& r){
	return vec2f(l.x-r.x, l.y-r.y);
}
vec2f operator*(const vec2f& l, const vec2f& r){
	return vec2f(l.x*r.x, l.y*r.y);
}
vec2f operator/(const vec2f& l, const vec2f& r){
	return vec2f(l.x/r.x, l.y/r.y);
}
vec2f operator*(const vec2f& l, float r){
	return vec2f(l.x*r, l.y*r);
}
vec2f operator/(const vec2f& l, float r){
	return vec2f(l.x/r, l.y/r);
}
vec2f operator*(float l, const vec2f& r){
	return r*l;
}
vec2f operator-(const vec2f& r){
	return vec2f(-r.x, -r.y);
}
bool operator==(const vec2f& l, const vec2f& r){
	return l.x==r.x && l.y==r.y;
}
bool operator!=(const vec2f& l, const vec2f& r){
	return !(l==r);
}

void pathTrace(const vec2f& path, std::vector<vec2i>& traversedPoints) {
	traversedPoints.clear();
	int x0 = 0, y0 = 0, x1 = (int) path.x, y1 = (int) path.y;
	bool steep = abs(y1 - y0) > abs(x1 - x0);
	if (steep) {
		std::swap(x0, y0);
		std::swap(x1, y1);
	}
	/*if (x0 > x1) {
		std::swap(x0, x1);
		std::swap(y0, y1);
	}*/
	int deltax = abs(x1 - x0);
	int deltay = abs(y1 - y0);
	int error = deltax / 2;
	int ystep;
	int xstep;
	int y = y0;
	if (y0 < y1)
		ystep = 1;
	else
		ystep = -1;
	if (x0 < x1)
		xstep = 1;
	else
		xstep = -1;

	for (int x = x0; x != x1; x+=xstep) {
		if (steep)
			traversedPoints.push_back(vec2i(y, x));
		else
			traversedPoints.push_back(vec2i(x, y));
		error = error - deltay;
		if (error < 0) {
			y += ystep;
			error += deltax;
		}
	}

}
void pointsInCircle(float magnitude, std::vector<vec2i>& occupiedPoints){
	occupiedPoints.clear();
	int iRadius=(int)ceilf(magnitude);
	for(int y=-iRadius; y<=iRadius; ++y){
		for(int x=-iRadius; x<=iRadius; ++x){
			vec2i point(x,y);
			if(point.magnitude()<=magnitude)
				occupiedPoints.push_back(point);
		}
	}
}



